﻿#include "WordEngine.h"

WordEngine::WordEngine():
    m_IsOpened(false),
    m_WordFileName(),
    m_Word(Q_NULLPTR),
    m_Documents(Q_NULLPTR),
    m_CurrentDocument(Q_NULLPTR)
{
    // 打开当前进程的COM
    OleInitialize(0);
}

WordEngine::WordEngine(const QString wordFileName):
    m_IsOpened(false),
    m_WordFileName(wordFileName),
    m_Word(Q_NULLPTR),
    m_Documents(Q_NULLPTR),
    m_CurrentDocument(Q_NULLPTR)
{
    // 打开当前进程的COM
    OleInitialize(0);
}

WordEngine::~WordEngine(void)
{
    release();

    // 关闭当前线程的COM库并释放相关资源
    OleUninitialize();
}

// 打开Word文档，如果不存在就创建
bool WordEngine::open(bool visible ,bool display_Alerts )
{
    if(m_WordFileName.isEmpty())
    {
        // 返回异常（word文件不存在，打开失败）
        return false;
    }

    QFile wordFile(m_WordFileName);
    if(!wordFile.exists())
    {
        // 以只读方式打开
        if(!wordFile.open(QIODevice::WriteOnly))
        {

            wordFile.close();
            // 返回异常（创建wordFile文件失败）
            return false;
        }

        wordFile.close();
    }else
    {
        if(!wordFile.open(QIODevice::ReadOnly))
        {

            wordFile.close();
            // 返回异常（文件正在被打开，请先关闭）
            return false;
        }

        wordFile.close();
    }

    // 操作Word的程序指针
    m_Word = new QAxObject;

    // 用Office的Word打开word文档
    bool flag = m_Word->setControl("Word.Application");

    if(!flag)
    {
        // 用WPS打开Word文档
        flag = m_Word->setControl("kwps.Application");

        if(!flag)
        {
            // 返回异常（Office的Word和WPS都无法打开）
            return false;
        }
    }

    // 打开时不显示程序窗体
    m_Word->dynamicCall("SetVisible(bool)", visible);

    // 不显示警告
    m_Word->setProperty("DisplayAlerts", display_Alerts);

    // 文档集
    m_Documents = m_Word->querySubObject("Documents");

    // 当前文档
    m_CurrentDocument = m_Documents->querySubObject("Open(const QString &)",m_WordFileName);

    if(m_CurrentDocument == Q_NULLPTR)
    {
        // 返回异常（当前活动文档不存在，打开失败）
        return false;
    }

    m_IsOpened = true;
    return m_IsOpened;
}

// 在书签处插入表格
// setMarks(const QString& strMark, const QString& strContent)会把书签删除。这样就不能反复更新文件了
QAxObject *WordEngine::insertTableIntoLabel(QString label_Name,QString table_Name,int rows,int columns)
{
    // 获取文档中的标签
    QAxObject *label = m_CurrentDocument->querySubObject("Bookmarks(QString)",label_Name);

    if(label == Q_NULLPTR)
    {
        // 返回异常（未发现 标签：label_Name ，插入表格失败）
        return Q_NULLPTR;
    }

    // 设置标签为选中状态
    label->dynamicCall("Select(void)");

    // 获取选中内容的区域
    QAxObject *labelSelection = m_Word->querySubObject("Selection");
    labelSelection->dynamicCall("InsertAfter(QString)", "\n");

    // 设置选中内容段落的格式 (设置对齐方式为居中)
    labelSelection->querySubObject("ParagraphFormat")->dynamicCall("Alignment","wdAlignParagraphCenter");

    // 设置表格的标题
    labelSelection->dynamicCall("TypeText(QString)",table_Name);

    // 获取书签的范围对象
    QAxObject *range = label->querySubObject("Range");

    // 获取当前文档的表格集对象
    QAxObject *tables = m_CurrentDocument->querySubObject("Tables");

    if(!tables)
    {
        // 返回异常（没有发现表格集）
        return Q_NULLPTR;
    }

    // 在返回对象中插入指定行列的表格（在range出插入表格）
    tables->dynamicCall("Add(QAxObject *,Long,Long)",range->asVariant(),rows,columns);

    // 获取具体单个的表对象
    QAxObject *table = tables->querySubObject("Table(int)",1);

    // 设置表格的样式（因为这样插入的表格是没有框线的）
    setTableFormat(table,rows,columns);

    return table;
}


// 向表格单元格插入数据
bool WordEngine::setTableCellString(QAxObject *table,QString cell_String,int row_Index,int column_Index)
{
    if(table == Q_NULLPTR)
    {
        // 返回异常（没有找到表格对象想，插入单元格内容失败）
        return false;
    }

    QAxObject *cell = table->querySubObject("Cell(int,int)",row_Index,column_Index);

    if(cell == Q_NULLPTR)
    {
        // 返回异常（单元格超界，插入单元格内容失败）
        return false;
    }

    // 能获取到cell就一定能获取到Range，因此不用异常检测
    QAxObject *cellRange = cell->querySubObject("Range");

    cellRange->dynamicCall("SetText(QString)",cell_String);
    return true;
}


// 光标移动到末尾
void WordEngine::cursorMoveToEnd(void)
{
    QAxObject *selection = m_Word->querySubObject("Selection");
    selection->dynamicCall("EndOf(QVariant &,QVariant &)",6,0);
}

// 设置表格的样式
void WordEngine::setTableFormat(QAxObject *table,int rows,int columns)
{
    // 将框线显示出来
    for(int i = 1;i <= 0; i++)
    {
        int index = 0 - i;

        // 这里的Borders()的参数,-1到-6分别值上、左、下、右、横、纵框线；-7：方向从左上角开始的斜向边框线；-8：方向从左下角开始的斜向边框线。
        QAxObject *border = table->querySubObject("Border(int)",index);

        // SetLineStyle参数参见：https://docs.microsoft.com/zh-cn/office/vba/api/word.wdlinestyle
        // 设置单实线
        border->dynamicCall("SetLineStyle(int)", "wdLineStyleSingle");
    }

    // 设置表格第一行字体样式
    for (int i = 1; i <= columns; i++)
    {
        QAxObject *cell = table->querySubObject("Cell(int,int)",1,i);
        QAxObject *cellRange = cell->querySubObject("Range");

        // 将单元格内容设置成加粗
        cellRange->dynamicCall("SetBold(int)",true);
    }

    // 设置表格第一列字体样式
    for (int i = 1; i <= rows; i++)
    {
        QAxObject *cell = table->querySubObject("Cell(int,int)",i,1);
        QAxObject *cellRange = cell->querySubObject("Range");

        // 将单元格内容设置成加粗
        cellRange->dynamicCall("SetBold(int)",true);
    }
}

// 保存
bool WordEngine::save(void)
{
    if(!m_IsOpened)
    {
        // 返回异常（文件没有打开，保存失败）
        return false;
    }

    QFile wordFile(m_WordFileName);

    if(wordFile.exists())
    {
        m_CurrentDocument->dynamicCall("Save()");

    }else
    {
        return this->saveAs(m_WordFileName);
    }
    return true;
}

// 另存为
bool WordEngine::saveAs(QString word_FileName)
{
    if(!m_IsOpened)
    {
        // 返回异常（文件没有打开，保存失败）
        return false;
    }

    QFile wordFile(m_WordFileName);

    if(wordFile.exists())
    {
        if(!wordFile.open(QIODevice::ReadOnly))
        {
            // 返回异常（文件正在打开，请先关闭）
            return false;
        }else
        {
            wordFile.close();
        }
    }

    m_CurrentDocument->dynamicCall("SaveAs(const QString &)",QDir::toNativeSeparators(word_FileName));
    return true;
}

// 关闭释放资源（对外函数）
void WordEngine::close(void)
{
    release();
}

// 释放相关资源
void WordEngine::release(void)
{
    m_IsOpened = false;

    if(m_CurrentDocument != Q_NULLPTR)
    {
        // wdDoNotSaveChanges       0     不保存待定的更改
        // wdPromptToSaveChanges	-2    提示用户保存待定更改
        // wdSaveChanges            -1    自动保存待定更改，而不提示用户
        m_CurrentDocument->dynamicCall("Close(QVariant)","wdDoNotSaveChanges");
        delete m_CurrentDocument;
        m_CurrentDocument = Q_NULLPTR;
    }

    if(m_Documents != Q_NULLPTR)
    {
        m_Documents->dynamicCall("Close(QVariant)","wdDoNotSaveChanges");
        delete m_Documents;
        m_Documents = Q_NULLPTR;
    }

    if(m_Word != Q_NULLPTR)
    {
        // m_Word->setProperty("DisplayAlerts", false);
        m_Word->dynamicCall("Close(QVariant)","wdDoNotSaveChanges");
        delete m_Word;
        m_Word = Q_NULLPTR;
    }
}



